package com.authsphere.security.account.common.bind;

import com.authsphere.common.result.ResponseResult;
import com.authsphere.plugin.api.WebExchange;
import com.authsphere.security.account.api.bind.AccountBindService;
import com.authsphere.security.account.api.bind.AccountNotBindContext;
import com.authsphere.security.account.common.config.SecurityAccountConfig;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler;

import java.io.IOException;
import java.util.Map;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/20 22:06
 **/
public abstract class AbstractAccountBindService extends AbstractAuthenticationTargetUrlRequestHandler implements AccountBindService {
    private static final Logger log = LoggerFactory.getLogger(AbstractAccountBindService.class);
    protected final SecurityAccountConfig.BindAccountConfig bindAccountConfig;
    public AbstractAccountBindService(SecurityAccountConfig.BindAccountConfig bindAccountConfig) {
        this.bindAccountConfig = bindAccountConfig;
    }

    @Override
    public void bind(WebExchange exchange) {
        HttpServletRequest request = exchange.getRequest();
        HttpServletResponse response = exchange.getResponse();
        if (!bindRequested(request, bindAccountConfig.getTokenParameter())) {
            log.debug("Social bind not requested.");
            return;
        }
        Authentication authentication = exchange.getAuthentication();
        if (!authentication.isAuthenticated()) {
            ResponseResult.result(response, ResponseResult.ofFailed(401, "认证失败，请重新登录"));
            exchange.setAbort(true);
        }
        if (authentication.getPrincipal() == null) {
            ResponseResult.result(response, ResponseResult.ofFailed(401, "用户信息不存在，请注册"));
            exchange.setAbort(true);
        }
        long timestamp = Long.parseLong(request.getParameter(bindAccountConfig.getTimestampParameter()));
        long currentTime = System.currentTimeMillis();
        if ((currentTime - timestamp) / 1000 > bindAccountConfig.getTimeout()) {
            log.warn("Third bind timeout.");
            if (!response.isCommitted()) {
                ResponseResult.result(response, ResponseResult.ofFailed(401, "第三方授权超时，请重新授权"));
                exchange.setAbort(true);
            }
            return;
        }
        onBind(exchange);
    }

    @Override
    public void noBind(HttpServletRequest request, HttpServletResponse response, AccountNotBindContext context) throws IOException {
        if (!handleRequested(request)) {
            log.warn("Third Not Bind not requested.");
            return;
        }
        onNoBind(request, response, context);
    }

    protected boolean handleRequested(HttpServletRequest request) {
        return true;
    }

    protected boolean bindRequested(HttpServletRequest request, String... parameters) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (String parameter : parameters) {
            if (!parameterMap.containsKey(parameter)) {
                log.debug(String.format("Did not handle social bind (principal did not set parameter '%s')", parameter));
                return false;
            }
        }
        return true;
    }

    /**
     * on third login failed cause not bind
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     * @param context AccountNotBindContext
     * @throws IOException IOException
     */
    protected abstract void onNoBind(HttpServletRequest request, HttpServletResponse response, AccountNotBindContext context) throws IOException;

    /**
     * on third bind
     * @param exchange WebExchange
     */
    protected abstract void onBind(WebExchange exchange);
}
